<?php
require_once( 'XmlDocument.php' );

class XmlParser {

	var $oParser;
	var $oDocument;
	var $aElementStack;

	function XmlParser( ) {
		$this->aElementStack = array();
		$this->oParser       = xml_parser_create();
		xml_set_object( $this->oParser, $this );
		xml_set_element_handler( $this->oParser, 'StartHandler', 'EndHandler' );
		xml_set_character_data_handler( $this->oParser, 'DataHandler' );
	}

	function Parse( $sXml, $sDocumentName = 'ParsedDocument' ) {

		$this->aElementStack = array();
		$this->_SetDocument( new XmlDocument( $sDocumentName ) );

		xml_parse( $this->oParser, $sXml );
		xml_parser_free( $this->oParser );
		
		$oDocument = $this->_GetDocument();
		
		if ( $oDocument->HasStructure() ) return $oDocument;

		return false;
	}

	function StartHandler( $oParser, $sName, $aAttributes ) {
		$oThisElement = new XmlElement( $sName );
		$oThisElement->AddAttributes( $aAttributes );
		$this->_PushOntoStack( $oThisElement );
	}

	function _GetStack() {
		return $this->aElementStack;
	}

	function _GetDocument() {
		return $this->oDocument;	
	}

	function _SetDocument( &$oDoc ) {
		$this->oDocument =& $oDoc;
	}

	function _PushOntoStack( &$oElement ) {
		array_push( $this->aElementStack, $oElement );	
	}

	function _PopOffStack() {
		return array_pop( $this->aElementStack );	
	}

	function _StackHasElements() {
		return $this->_GetNumberOfElementsOnStack() > 0;
	}
	
	function _GetNumberOfElementsOnStack() {
		return count( $this->aElementStack );
	}

	// TODO: Surely these parameter aren't needed - unless you use the name to check the name of the element you're popping'?
	function EndHandler( $oParser, $sName ) {

		$oThisElement = $this->_PopOffStack();
		
		if ( $oThisElement === null ) return false;	

		if ( $this->_StackHasElements() ) {
			$oThisElementsParent = $this->_PopOffStack();
			$oThisElementsParent->AddElement( $oThisElement );
			$this->_PushOntoStack( $oThisElementsParent );
		} else {
			$this->oDocument->AddElement( $oThisElement );
		}
		
		return true;
	}

	function DataHandler( $oParser, $sData ){
		if ( trim( $sData ) != '' ) {

			$oThisElement = $this->_PopOffStack();

			if ( $oThisElement === null ) return false;

			$oThisElement->SetContent( $sData );                  // TODO: Only supports one lot of content per tag
			$this->_PushOntoStack( $oThisElement );
		}
		
		return true;

	}
}
?>